package com.junhong.forum.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.List;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.inject.Inject;

import org.slf4j.Logger;

import com.junhong.forum.common.Constants;
import com.junhong.forum.entity.AbstractEntity;
import com.junhong.forum.entity.Affiliate;
import com.junhong.forum.entity.ForumThread;
import com.junhong.forum.entity.InternalLink;
import com.junhong.forum.entity.Store;
import com.junhong.util.StringUtil;
import com.junhong.util.WebConfigUtil;

/**
 * Session Bean implementation class BuildLinkEjb
 */
@Stateless
@LocalBean
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class BuildLinkEjb {
	@Inject
	private StoreEjb							storeEjb;

	@Inject
	private GenericCRUDService<InternalLink>	genericInternalLinkEjb;

	@Inject
	Logger										logger;

	/**
	 * Default constructor.
	 */
	public BuildLinkEjb() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * build affiliate link based on the original link this will be used for links in thread
	 * 
	 * @param content
	 * @return
	 */
	public String buildAffiliateLinkNPopStore(String content, AbstractEntity forumThreadOrReply) {
		List<String> htmlLinkList = StringUtil.getHtmlLink(content);
		// set store
		Store store = null;
		for (String link : htmlLinkList) {
			store = getStore(link);
			break;
		}
		if (store != null) {
			if (forumThreadOrReply instanceof ForumThread) {
				((ForumThread) forumThreadOrReply).setStore(store);

			}
		}

		// build affiliate link
		String domain = WebConfigUtil.getProp(Constants.DOMAIN);
		if (StringUtil.isNullOrBlank(domain)) {
			logger.error("can not load domain from environ.ini, the internal Link can not be generated");
		} else {
			String internalLinkPattern = domain + "/procLink?pid=";
			for (String link : htmlLinkList) {
				if (link.contains(internalLinkPattern)) {
					continue;
				}
				InternalLink interLink = new InternalLink();
				String affiliateLink = convertToAffiliateLink(link, interLink);
				// generate internal link
				interLink.setLinkURL(affiliateLink);
				if (forumThreadOrReply instanceof ForumThread) {
					interLink.setThread((ForumThread) forumThreadOrReply);
				}
				genericInternalLinkEjb.create(interLink);
				// replace link with the affiliate link
				int index = content.indexOf(link);
				int begin = 0;
				while (index != -1) {
					content = content.substring(0, index) + internalLinkPattern + interLink.getId() + content.substring(index + link.length());
					begin = index + link.length();
					index = content.indexOf(link, begin);

				}

			}
		}
		return content;
	}

	/**
	 * this will be used for links in reply
	 * 
	 * @param content
	 * @return
	 */
	public String buildAffiliateLink(String content) {
		List<String> htmlLinkList = StringUtil.getHtmlLink(content);

		// build affiliate link
		for (String link : htmlLinkList) {
			String affiliateLink = convertToAffiliateLink(link, null);
			if (affiliateLink == null || content.contains(affiliateLink)) {
				continue;
			}
			if (affiliateLink != null) {
				int index = content.indexOf(link);
				if (index != -1) {
					content = content.substring(0, index) + affiliateLink + content.substring(index + link.length());
				}
			}

		}
		return content;
	}

	/**
	 * parse the link to get domain, then map and get the store
	 * 
	 * @param link
	 * @return
	 */
	public Store getStore(String link) {
		Store result = null;
		String domain = StringUtil.getDomain(link);
		if (!StringUtil.isNullOrBlank(domain)) {
			domain = domain.toUpperCase();
			result = storeEjb.getStoreByDomain(domain);
		}
		return result;
	}

	/**
	 * convert original link to affiliated link
	 * 
	 * @param link
	 * @return
	 */
	public String convertToAffiliateLink(String link, InternalLink internalLink) {
		link = link.replace("&amp;", "&");
		String result = link;
		Store store = getStore(link);
		if (store != null) {
			Affiliate affiliate = store.getAffiliate();
			// if affiliate is there, then build affiliate link
			if (affiliate != null) {
				// link = link.replace("&amp;", "&");
				if (affiliate.getName().equalsIgnoreCase(Constants.CJ)) {
					String urlPattern = affiliate.getUrlPattern();
					if (!StringUtil.isNullOrBlank(affiliate.getPublishId()) && !StringUtil.isNullOrBlank(store.getRedirectLinkId())) {
						urlPattern = urlPattern.replace("{PID}", affiliate.getPublishId());
						// urlPattern = urlPattern.replace("{AID}",
						// store.getRedirectLinkId());
						urlPattern = urlPattern.replace("{RedirectLink}", link);
						result = urlPattern;
					} else {
						result = link;
					}
					// replace param and return link back;

				} else if (affiliate.getName().equalsIgnoreCase(Constants.CJ_NODLG)) {
					String urlPattern = affiliate.getUrlPattern();
					if (!StringUtil.isNullOrBlank(affiliate.getPublishId()) && !StringUtil.isNullOrBlank(store.getRedirectLinkId())) {
						urlPattern = urlPattern.replace("{PID}", affiliate.getPublishId());
						urlPattern = urlPattern.replace("{AID}", store.getRedirectLinkId());
						urlPattern = urlPattern.replace("{RedirectLink}", link);
						result = urlPattern;
					} else if (StringUtil.isNullOrBlank(store.getRedirectLinkId()) && !StringUtil.isNullOrBlank(store.getGenericStoreLink())) {
						/*
						 * if advertiser does not support deeplink, store.Redirectlink will be blank, then replace link with genericStoreLink. if user
						 * click this link and search the product they want to buy, it still valid for commission. the problem is that the link will
						 * not direct user the specific deal they want, in this case, it is .
						 */
						result = store.getGenericStoreLink();

					} else {
						result = link;
					}
					// replace param and return link back;

				} else if (affiliate.getName().equalsIgnoreCase(Constants.LINKSHARE)) {
					// call linkshare to get affiliate link
					if (link.contains(affiliate.getPublishId())) {
						result = link;
					} else {
						if (!StringUtil.isNullOrBlank(affiliate.getToken()) && !StringUtil.isNullOrBlank(store.getRedirectLinkId())) {
							StringBuilder requestURL = new StringBuilder(Constants.GENDEEPLINKPREFIX).append(affiliate.getToken()).append("&mid=")
									.append(store.getRedirectLinkId()).append("&murl=").append(link);
							BufferedReader in = null;
							try {
								URL genDeepLink = new URL(requestURL.toString());
								in = new BufferedReader(new InputStreamReader(genDeepLink.openStream()));
								String inputLine;
								StringBuilder response = new StringBuilder();
								while ((inputLine = in.readLine()) != null) {
									response.append(inputLine);
								}
								if (response.toString().contains("http://")) {
									result = response.toString();
									// add u1 right before redirect link
									result = result.replace("&RD_PARM1", "&u1=deallover&RD_PARM1");
								}
							} catch (IOException ex) {
								logger.error("cause {}, message {}", ex.getCause(), ex.getMessage());
								result = link;

							} finally {
								if (in != null) {
									try {
										in.close();
									} catch (IOException ioExp) {
										ioExp.printStackTrace();
										logger.error("can not close connection, cause{}, message {}", ioExp.getCause(), ioExp.getMessage());
									}
								}
							}
						}
					}

				} else if (affiliate.getName().equalsIgnoreCase("WWW.AMAZON.COM")) {
					// if it already have out tag
					if (link.contains(affiliate.getPublishId())) {
						result = link;
					} else {
						// it has other's tag
						link = URLDecoder.decode(link);
						int index = link.indexOf("tag=");
						if (-1 != index) {
							link = link.substring(0, index);
						}
						if (!StringUtil.isNullOrBlank(affiliate.getUrlPattern())) {
							String urlPattern = affiliate.getUrlPattern();
							String publishId = "";
							if (!link.contains("?")) {
								publishId = "?tag=" + affiliate.getPublishId();
							} else {
								publishId = "&tag=" + affiliate.getPublishId();
							}
							result = urlPattern.replace("{PUBLISHID}", publishId).replace("{YOURHOTDEAL_AMAZONANYLINK}", link);
						}
					}
				} else if (affiliate.getName().equalsIgnoreCase(Constants.EBAYPARTNERNETWORK)) {
					if (link.contains(affiliate.getPublishId())) {
						result = link;
					} else {
						if (!StringUtil.isNullOrBlank(affiliate.getUrlPattern())) {
							String urlPattern = affiliate.getUrlPattern();
							result = urlPattern.replace("{PUBLISHID}", affiliate.getPublishId()).replace("{CAMPAIGNID}", store.getRedirectLinkId())
									.replace("{CUSTOMURL}", URLEncoder.encode(link));
						}
					}
				} else if (affiliate.getName().equalsIgnoreCase(Constants.PEPPERJAM)) {
					if (link.contains(affiliate.getPublishId())) {
						result = link;
					} else {
						if (!StringUtil.isNullOrBlank(affiliate.getUrlPattern())) {
							String urlPattern = affiliate.getUrlPattern();
							result = urlPattern.replace("{STOREGENERICLINKURL}", store.getRedirectLinkId()).replace("{CUSTOMURL}",
									URLEncoder.encode(link));
						}
					}

				} else if (affiliate.getName().equalsIgnoreCase(Constants.SHAREASALE)) {
					if (link.contains(affiliate.getPublishId())) {
						result = link;
					} else {
						if (!StringUtil.isNullOrBlank(affiliate.getUrlPattern())) {
							String urlPattern = affiliate.getUrlPattern();
							result = urlPattern.replace("{PUBLISHID}", affiliate.getPublishId())
									.replace("{BANNER_MERCHANT_ID}", store.getRedirectLinkId()).replace("{CUSTOMURL}", URLEncoder.encode(link));
						}
					}

				} else if (affiliate.getName().equalsIgnoreCase(Constants.SKIMLINKS)) {
					String urlPattern = affiliate.getUrlPattern();
					if (!StringUtil.isNullOrBlank(affiliate.getPublishId())) {
						urlPattern = urlPattern.replace("{PID}", affiliate.getPublishId());
						urlPattern = urlPattern.replace("{RedirectLink}", URLEncoder.encode(link));
						String websiteURL = WebConfigUtil.getProp(Constants.DOMAIN);
						if (!websiteURL.contains("http://")) {
							websiteURL = "http://" + websiteURL;
						}
						urlPattern = urlPattern.replace("{SREF}", URLEncoder.encode(websiteURL));
						result = urlPattern;
					} else {
						result = link;
					}
				} else if (affiliate.getName().equalsIgnoreCase(Constants.VIGLINK)) {
					String urlPattern = affiliate.getUrlPattern();
					if (!StringUtil.isNullOrBlank(affiliate.getPublishId())) {
						urlPattern = urlPattern.replace("{PID}", affiliate.getPublishId());
						urlPattern = urlPattern.replace("{RedirectLink}", URLEncoder.encode(link));
						result = urlPattern;
					} else {
						result = link;
					}
				}
			}

		}
		// if called for thread links, internalLink will be set with store.
		// otherwise,
		// internalLink will be null for reply links
		if (internalLink != null) {
			internalLink.setStore(store);
			if (store != null) {
				internalLink.setCashBackPct(store.getCashBackPercent());
			} else {
				internalLink.setCashBackPct(BigDecimal.ZERO);
			}
		}
		return result;
	}
}
